package com.demo.user.aop;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.demo.common.pojo.dto.OperationLogsDTO;
import com.demo.user.constants.JwtClaimsConstant;
import com.demo.user.context.BaseContext;
import com.demo.user.pojo.dto.*;
import com.demo.user.pojo.vo.LoginVO;
import com.demo.user.result.Result;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.transaction.annotation.ShardingSphereTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;


import static com.demo.common.constants.MQConstants.LOGGING_EXCHANGE;
import static com.demo.common.constants.MQConstants.LOGGING_RECEIVE_KEY;

@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class LogAspect {

    private final RabbitTemplate rabbitTemplate;

    @Order(1)
    @Around("execution(* com.demo.user.controller.*.*(..))")
    public Object sendLog(ProceedingJoinPoint joinPoint){
        //创建日志对象
        OperationLogsDTO operationLogsDTO = new OperationLogsDTO();
        //雪花算法生成id
        operationLogsDTO.setLogId(IdWorker.getId());
        // 获取HttpServletRequest对象
        ServletRequestAttributes attributes =
                (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 直接获取客户端IP
        String ip = request.getRemoteAddr();
        //处理IPv6本地地址
        if ("0:0:0:0:0:0:0:1".equals(ip)) {
            ip = "127.0.0.1";
        }
        // 设置IP到日志对象
        operationLogsDTO.setIp(ip);
        //获取执行的方法名
        String methodName = joinPoint.getSignature().getName();
        //根据不同的方法名执行不同的方法
        Object object = null;
        if ("register".equals(methodName)){
            operationLogsDTO.setAction("用户注册");
            //获取参数
            RegisterDTO registerDTO =(RegisterDTO) joinPoint.getArgs()[0];
            try {
                //执行方法
                object = joinPoint.proceed();
                operationLogsDTO.setDetail("用户名："+registerDTO.getUsername()+"注册成功");
            } catch (Throwable e) {
                operationLogsDTO.setDetail("用户名："+registerDTO.getUsername()+"注册失败");
                throw new RuntimeException(e);
            } finally {
                rabbitTemplate.convertAndSend(LOGGING_EXCHANGE, LOGGING_RECEIVE_KEY, operationLogsDTO);
            }
        }else if ("login".equals(methodName)){
            operationLogsDTO.setAction("用户登录");
            //获取参数
            LoginDTO registerDTO =(LoginDTO) joinPoint.getArgs()[0];
            try {
                //执行方法
                object = joinPoint.proceed();
                //获取返回结果
                Result result = (Result) object;
                LoginVO loginVO =(LoginVO) result.getData();
                if (ObjectUtil.isNotNull(loginVO)) {
                    operationLogsDTO.setUserId(loginVO.getId());
                    operationLogsDTO.setDetail("用户名："+registerDTO.getUsername()+"登录成功");
                }else {
                    operationLogsDTO.setDetail("用户名："+registerDTO.getUsername()+"登录失败");
                }
            } catch (Throwable e) {
                operationLogsDTO.setDetail("用户名："+registerDTO.getUsername()+"登录失败");
                throw new RuntimeException(e);
            } finally {
                rabbitTemplate.convertAndSend(LOGGING_EXCHANGE, LOGGING_RECEIVE_KEY, operationLogsDTO);
            }
        } else if ("getUserById".equals(methodName)) {
            //获取当前用户的id
            operationLogsDTO.setUserId((Long) BaseContext.getCurrentUser().get(JwtClaimsConstant.USER_ID));
            operationLogsDTO.setAction("获取用户信息");
            try {
                Long userId =(Long) joinPoint.getArgs()[0];
                object = joinPoint.proceed();
                operationLogsDTO.setDetail("查询用户id为：" + userId + "的信息" );
            } catch (Throwable e) {
                operationLogsDTO.setDetail("查询用户信息失败");
                throw new RuntimeException(e);
            } finally {
                rabbitTemplate.convertAndSend(LOGGING_EXCHANGE, LOGGING_RECEIVE_KEY, operationLogsDTO);
            }
        }else if("userPageQuery".equals(methodName)){
            operationLogsDTO.setUserId((Long) BaseContext.getCurrentUser().get(JwtClaimsConstant.USER_ID));
            operationLogsDTO.setAction("用户分页查询");
            try {
                object = joinPoint.proceed();
                operationLogsDTO.setDetail( "分页查询用户信息，角色为：" + BaseContext.getCurrentUser().get(JwtClaimsConstant.USER_ROLE));
            } catch (Throwable e) {
                operationLogsDTO.setDetail("用户分页查询失败");
                throw new RuntimeException(e);
            } finally {
                rabbitTemplate.convertAndSend(LOGGING_EXCHANGE, LOGGING_RECEIVE_KEY, operationLogsDTO);
            }
        }else if("updateUser".equals(methodName)){
            operationLogsDTO.setUserId((Long) BaseContext.getCurrentUser().get(JwtClaimsConstant.USER_ID));
            operationLogsDTO.setAction("更新用户信息");
            try {
                Long userId =(Long) joinPoint.getArgs()[0];
                UpdateDTO updateDTO =(UpdateDTO) joinPoint.getArgs()[1];
                object = joinPoint.proceed();
                operationLogsDTO.setDetail("更新用户id为：" + userId + "的信息" + updateDTO);
            } catch (Throwable e) {
                operationLogsDTO.setDetail("更新用户信息失败");
                throw new RuntimeException(e);
            } finally {
                rabbitTemplate.convertAndSend(LOGGING_EXCHANGE, LOGGING_RECEIVE_KEY, operationLogsDTO);
            }
        }else if ("resetPassword".equals(methodName)){
            operationLogsDTO.setUserId((Long) BaseContext.getCurrentUser().get(JwtClaimsConstant.USER_ID));
            operationLogsDTO.setAction("重置密码");
            try {
                ResetPasswordDTO resetPasswordDTO =(ResetPasswordDTO) joinPoint.getArgs()[0];
                object = joinPoint.proceed();
                operationLogsDTO.setDetail("重置用户id为：" + resetPasswordDTO.getUserId() + "的密码");
            } catch (Throwable e) {
                operationLogsDTO.setDetail("重置密码失败");
                throw new RuntimeException(e);
            } finally {
                rabbitTemplate.convertAndSend(LOGGING_EXCHANGE, LOGGING_RECEIVE_KEY, operationLogsDTO);
            }
        }else if ("modifyPermissions".equals(methodName)){
            operationLogsDTO.setUserId((Long) BaseContext.getCurrentUser().get(JwtClaimsConstant.USER_ID));
            operationLogsDTO.setAction("修改权限");
            try {
                ModifyPermissionsDTO modifyPermissionsDTO =(ModifyPermissionsDTO) joinPoint.getArgs()[0];
                object = joinPoint.proceed();
                operationLogsDTO.setDetail("修改用户id为：" + modifyPermissionsDTO.getUserId() + "的权限为：" + modifyPermissionsDTO.getRoleCodes());
            } catch (Throwable e) {
                operationLogsDTO.setDetail("修改权限失败");
                throw new RuntimeException(e);
            } finally {
                rabbitTemplate.convertAndSend(LOGGING_EXCHANGE, LOGGING_RECEIVE_KEY, operationLogsDTO);
            }
        }
        return object;
    }
}
